using System;
using System.Collections.Generic;
using NAsserter.Impl;

namespace NAsserter
{
    /// <summary>
    /// This is used to perform assertions against arguments.  The purpose is to make assertion 
    /// </summary>
    /// <typeparam name="T">The type of the argument.</typeparam>
    public interface IArgumentExpressions<T> : IBaseArgumentExpression, IHideObjectMembers
    {
        string Description { get; }

        string Name { get; }

        /// <summary>
        /// The value of the argument that assertions will be made against.
        /// </summary>
        T Value { get; }

        /// <summary>
        /// Evaluate a Range expression.
        /// </summary>
        /// <returns>A nested ArgumentExpressionsImpl for method chaining.</returns>
        IBetweenExpression<T> Between(T start);

        /// <summary>
        /// Throws an exception if the argument value does not exist within the target args.
        /// </summary>
        /// <param name="args">The available values that the argument must exist within.</param>
        /// <exception cref="NotExistsArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> Exists(params T[] args);

        /// <summary>
        /// Throws an exception if the argument value does not exist within the target args.
        /// </summary>
        /// <param name="existsInEnumerable">The available values that the argument must exist within.</param>
        /// <exception cref="NotExistsArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> Exists(IEnumerable<T> existsInEnumerable);

        /// <summary>
        /// Allows for method chaining of a boolean condition.
        /// </summary>
        /// <param name="resultFromExpression">A boolean which is a result of an expression.</param>
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> If(bool resultFromExpression);

        /// <summary>
        /// Allows for method chaining of a boolean condition.
        /// </summary>
        /// <param name="condition">A predicate expressing a boolean condition.</param>
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> If(Predicate<T> condition);

        IArgumentExpressions<T> Is(T value);

        IArgumentExpressions<T> IsNot(T value);

        /// <summary>
        /// Throws an exception if the argument value is its default value based on its type.
        /// </summary>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> IsNotDefault();

        /// <summary>
        /// Throws an exception if the argument value is a null value.
        /// </summary>
        /// <exception cref="ArgumentNullException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> IsNotNull();

        /// <summary>
        /// Throws an exception if the argument value is Null or an empty string..
        /// </summary>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> IsNotNullOrEmpty();

        /// <summary>
        /// Throws an exception if condition does not evaluate to False.
        /// </summary>
        /// <param name="condition">Condition to be evaluated.</param>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> IsFalse(Predicate<T> condition);

        /// <summary>
        /// Throws an exception if condition does not evaluate to True.
        /// </summary>
        /// <param name="condition">Condition to be evaluated.</param>
        /// <exception cref="ArgumentException" />
        /// <returns>An root ArgumentExpressionsImpl for method chaining.</returns>
        IArgumentExpressions<T> IsTrue(Predicate<T> condition);

        /// <summary>
        /// Allows for an expression to be evaluated against this arguments property.
        /// </summary>
        /// <typeparam name="TProp">The type of the target property's value.</typeparam>
        /// <param name="valueCallback">An expression returning the target property's value.</param>
        /// <param name="name">The name of the target property.</param>
        /// <returns>A nested PropertyArgumentExpression for method chaining assertions of this property.</returns>
        PropertyArgumentExpression<T, TProp> Property<TProp>(Func<T, TProp> valueCallback, string name);
    }
}